How to "eat resources for breakfast"
By Richard Bennett
Copyright (c) 1991 Apple Users' Group, Sydney
Republished from Applecations, a publication of the Apple Users' Group, Sydney, Australia.
When System 5 arrived for the Apple IIgs, with it came some very powerful programming tools, unfortunately without the same fanfare as that reserved for the System 5 version of Quickdraw II. Yes, we all remember how fast 20 windows open and close! One of these new tools was the Resource Manager, and whether you like it or not, it has been quietly manipulating the resources in your system ever since you started running System 5.
So what is a resource? Hoping to find an appropriate analogy, I cleverly dived into the dictionary. Ooops, wrong move. "a source of supply, support, or aid". Well in a sense, yes. On the IIgs, a resource is a collection of bytes grouped together, and referenced by a unique number. For example, to draw a menu using the tools from System 4, a programmer would have to write something like this, in pseudo-code:
the file menu has the characters " file " in its title
the first item on the menu is "--New\*Nn"
the next one is "--Open\*Oo"
and then "--Close\*Ww"
put them together into a menu
add the file menu to the menu bar
make this menu bar the system menu bar
And that's only for the " file " menu. Now although it's a rather simple example, under System 5 you only have to do this:
make the current system menu bar from resource number 1
Of course the resource referenced by the number 1 must already be created, but once that is done, it never has to be tampered with again. Because the resource is created separately, the compilation or assembly time of your program is dramatically decreased. Also, if you need to change any of the resources, for example a string of text, or an icon, you can change the resource directly, without having to re-assemble or re-compile the program. The other major benefit, is that because the Resource Manager is looking after the resources for you, you don't have to worry about memory management, as the Resource Manager automatically keeps track of all your resources, and loads them whenever necessary. It will also automatically purge them when not being used, thus saving valuable system memory.
In your System 5 SYSTEM: folder, there is a file called SYS.RESOURCES. This file contains all of the resources which System 5 itself requires to run. Included are all the system error messages, and a couple of menu items for the Alphabet CDEV.
So in theory, you should be able to launch BASIC.SYSTEM, BLOAD the file, and look at all the resources right? Wrong! I'll save you the trouble, they aren't there. So where are the resources kept when they are not in memory? Well they are kept on disk, inside a new type of ProDOS file which was also introduced with System 5.
Under the original ProDOS, a file is defined as a collection of data bytes, stored on disk blocks, which are all joined together by a kind of chain. No matter where the chain is stretched over the disk, the description of the file is still kept in the same place, the catalog. So although the catalog shows the file as being in a particular subdirectory, the chain of data could stretch virtually anywhere all over the disk. That's where ProDOS and GS/OS come in, as they make sense of all these chains, and pass the appropriate data to the application program. BASIC.SYSTEM allows you to access the data in the file using various commands from Applesoft, and that is its only function.
Now imagine that there are two separate chains belonging to the same file. The first one still contains all of the information it did before, however now there is another chain completely independent of it, but is still part of the original file. So if the file is moved or copied, both chains belong to the file, so both chains are actually moved or copied. We can now place our resources into the second chain, and they remain invisible to the user or application. The only problem, is how to access it.
These new files are called "extended files", and the two chains are called the "data fork", because it contains the data that a normal file contains, and the "resource fork", because it contains resources. (the resource fork doesn't have to contain resources, and can simply be used as a second data fork, however I've yet to hear of anyone using it for that purpose)
The ProDOS FST, found in the SYSTEM:FSTS: subdirectory, has been updated so that a programmer can access either fork of an extended file. When your program requests a file to be opened, there is an extra parameter that specifies which fork you would like to open.
To understand the concept of an File System Translator (FST), keep in mind that where GS/OS is concerned, ProDOS is simply just another filing system that GS/OS understands. GS/OS is an operating system which can read any filing system as long as an FST exists for it. So in theory, it is possible for GS/OS to work with DOS 3.3, Pascal, HFS (silly Macintosh filing system) or even MS-DOS! ProDOS 8 however, can only access the ProDOS filing system.
Unfortunately, ProDOS 8 cannot access extended files, and it doesn't look as though Apple intends it to either. If you try to access an extended file under ProDOS 8, you will get a $4B error, which indicates an "unsupported storage type", which as we now know is of course true! (you would have got
this error if you tried to BLOAD the SYS.RESOURCES file that was mentioned previously)
As should now be obvious, there are two distinct ProDOS file structures on the IIgs. The first is standard ProDOS, which is controlled by ProDOS 8 and the GS/OS ProDOS FST, and the second is the GS/OS extension to standard ProDOS, which is controlled by the GS/OS ProDOS FST only. If you have extended files on a ProDOS volume, then that volume is considered as being a GS/OS controlled ProDOS volume, and only GS/OS aware programs are capable of manipulating the extended files on it. ProDOS 8 utilities, such as Cat Doctor and Copy II Plus, are unable to handle extended files, because they do not run under GS/OS, and in most cases, programs written before extended files existed can even damage the data on your disks if they try to manipulate them. So if you must use ProDOS 8 utility programs to manipulate data on a GS/OS controlled volume, make sure you are using the latest version, and that it is aware of extended files.
So now we all know what a resource fork is, which is great, however the original question was 'What is a resource?'. When the resource fork is being used to house resources, remembering that the resource fork doesn't necessarily contain resources, it is maintained by the Resource Manager. The Resource Manager keeps a map at the beginning of the fork, so it knows where each resource is actually kept within the fork. After the map comes the actual resources.
We can compare this map and its associated resources with a ProDOS disk. A ProDOS disk contains a directory (CATALOG) and files, likewise a resource fork contains a map and resources. The main differences are that resources do not have names, they have numbers, known as a 'resource ID'. Apart from that, they both have a type (a resource has a resource type which dictates what the resource is used for, and its structure, just like a file type), a size, and attributes. A ProDOS file has attributes which describe whether it is locked, backed up, invisible, read only, write only or renamable. A resource has attributes which describe what attributes the Memory Manager will use when the resource is loaded, whether it is read only, loaded whenever the file is opened, or whether it requires a special 'converter' program to be able to load the resource into memory. GS/OS files can also have 'converter' programs, of which the most common example is SYS16 or S16 files which require the System Loader to load the file and relocate it in memory before it is able to run. Resource 'converters' work on the same principle.
Basicly the resource fork is a mini-filing system, which is controlled by the Resource Manager, instead of ProDOS or GS/OS. Because it is not an entire filing system, it does have a number of limitations, the main one being the inability to give a resource a name. However there is way, and I will get to that a bit later, but for now keep in mind
that it can be done by the programmer if he or she wishes to.
So who uses these resources which we keep hearing about? Well by now most people should have HyperCard IIGS, which is great because it uses resources more than any other program that I've come across, and it provides an excellent example which everyone is familiar with.
Whenever you use an icon in a stack, for example as a button, you can identify it either by its name, or its ID. The ID is simply the resource ID of the icon, and the name is the resource name of the icon (remember, I'll explain that soon!). The icon, as you've probably already guessed, is stored as a resource in a resource fork.
When a program asks the Resource Manager for a specific resource, the Resource Manager scans all of the currently open resource forks, and loads the first resource it finds that matches the resource ID and resource type which the program requested. Yes, there can be a number of resource forks 'open' at one time, all maintained by the Resource Manager. When a program starts to run, and it tells the Resource Manager it would like to 'do business' (this is called 'logging in to the Resource Manager', and involves issuing an incorrectly named _ResourceStartUp call). The Resource Manager then opens the resource fork of the program, and keeps it 'open for business'. When the program shuts down (quits), it tells the Resource Manager it's finished (this is called 'logging out', and is invoked with the _ResourceShutDown call). When HyperCard IIGS starts, it logs in to the Resource Manager. Whenever you open a stack, HyperCard tells the Resource Manager to open its resource fork as well.
If you create a button with HyperCard IIGS, and click 'Icon' from the button's edit dialog, you will be presented with a selection of icons from which to choose. If you click once on one of the icons, the information regarding that icon is displayed at the top of the dialog, and looks something like this:
ID: 1002 "Icon 1" from "HYPERCARDIIGS"
This tells us that there is an icon called "Icon 1", with a resource ID of 1002, and that it is currently residing in the resource fork of the file HYPERCARDIIGS. From this we can assume that if a stack uses this icon, we can leave it where it is, because if it comes with the HYPERCARDIIGS program, everyone should have access to it! What about this example:
ID: 1003 "My icon" from "My.Stack"
In this case, we have an icon called "My icon", with a resource ID of 1003, but it is currently in the resource fork of the file "My.Stack". If you were working on another stack called "This.Stack", and you selected this icon, you
would have to make sure that "My.Stack" is always open whenever you wish to use the icon. An easier way would be if the icon was actually part of the stack you were working on, which means HyperCard IIGS would have already opened the resource fork, thus giving you access to it. If you click on 'Import' from the icon dialog, HyperCard IIGS will copy the icon from where it is now, to your current stack.
Now although the above example may seem complicated at first, it is a good example of how HyperCard is disguising its resources (no pun intended) as resources, and in reality you are actually manipulating resources and resource forks. And you thought only programmers used resource forks! HyperCard sounds are also stored as resources, as are XCMDs and XFCNs.
XCMDs and XFCNs are programs which your scripts can call at any time. If you had an XCMD called "explode", you would invoke it with the normal message sending routine.
on mouseup
explode
end mouseup
HyperCard IIGS sends the message "explode" down its hierarchy, until it gets to 'Stack'. If the stack script ignores the message, or passes it on (using the 'pass' command), HyperCard looks for a resource called "explode", with a resource type of XCMD. Unlike before, HyperCard tells the Resource Manager only to look for the XCMD in the resource fork belonging to the stack. If not found, HyperCard passes it on to the Home stack and all of its handlers. If the XCMD is found, it is loaded from the resource fork, via the Resource Manager, and 'converted' into a program. Because an XCMD is to be used as a program, it is stored as a relocatable object file, the same as a SYS16 or S16 file. In this case, the converter attribute is set for the resource, and the Resource Manager correctly converts the resource into a relocated program, via the System Loader. When HyperCard again gets control, it simply calls the program (XCMD), which returns with the results. In our example, we end up with a very dead mouse! Squeek....
As mentioned before, each resource has an ID, and a type. The type indicates what the resource is going to be used for, just like a file type under ProDOS. An icon resource is called an 'rIcon' (stands for: resource Icon), and its type is $8001 (in hexadecimal). To load a resource, the Resource Manager needs to know the resource ID and the resource type, in this case $8001. Another type of resource is the rResName resource type, which is $8014. An rResName resource contains a list of names and numbers, of which the numbers correspond with the resource IDs of other resources in the resource fork. The resource ID of the rResName resource indicates which resource type this rResName resource refers to. Still with me? For an application program to load in a resource by its name, it tells the Resource Manager to load the resource
of type $8014 (rResName) and resource ID which corresponds with the type of resource the application is looking for, such as $8001 for an icon. It then has to scan the resource looking for the name it wants, retrieve the number that corresponds with it, and pass this resource ID with the original resource type, to the Resource Manager. As usual the Resource Manager simply loads the resource, completely ignorant of all the trouble the application just went through!
So to answer whether names can be used with resources, yes, but it's up to the programmer (such as the programmers of HyperCard IIGS), and the Resource Manager couldn't care less.
Now no Apple II article is ever complete without at least a touch of technical information for the old hackers amongst us, so let's move on to the structure of a resource fork.
The resource fork contains only one fixed offset data block. The resource file header (ResHeaderRec) is the very first record of the fork, and contains four fields. They are: rFileVersion (the version number of the layout of the resource fork. The current version is 0), rFileToMap (this is the offset in bytes from the beginning of the resource fork to the resource map. I mentioned previously that the map was at the beginning. So I lied!), rFileMapSize (the size in bytes of the map), and rFileMemo (128 bytes of information which your application can use for anything. The Resource Manager, as usual, couldn't care less what you use it for). When the Resource Manager opens the resource fork, it checks this record for the offset and size of the map, and loads the map into memory.
The map contains all the information the Resource Manager needs to correctly maintain the resource fork. It consists of: mapNext (when the map is on disk, this field is undefined, when in memory, it contains the Handle of the next map which the Resource Manager is looking after), mapFlag (when in memory, this flag indicates whether the map has been changed and needs to be written back to disk at some stage), mapOffset (this is the same offset that was stored in the ResHeaderRec), mapSize (also a copy of the size in the ResHeaderRec), mapToIndex (this is the offset in bytes from the beginning of the map, to the beginning of the mapIndex. The mapIndex can be considered as being the directory of the resource fork), mapFileNum (this is the GS/OS reference number which was returned when this resource fork was opened), mapID (when a resource fork is opened, the Resource Manager assigns it a special number, called the file ID, not to be confused with the GS/OS reference number. This is it folks!), and a number of other fields describing the free areas of the resource fork and which entries in the index are relevant.
The mapIndex array contains a resource reference record (ResRefRec) for each resource in the resource fork. Each ResRefRec contains the resource's type, its resource ID, the offset in bytes from the beginning of the resource fork to
the resource, its attributes, its size, and where it currently is in memory if it is loaded.
The Resource Manager maintains all of these fields for the programmer. If a resource is changed, the attributes of the resource change to include a resChanged attribute, which we know is stored in the ResRefRec. When the resource fork is closed, the Resource Manager scans the mapIndex array looking for resources which have changed. Whenever it finds one, it finds room in the resource fork, and writes it back to disk. Once all the resources have been written, it checks the mapFlag to see if the map has changed, and if so writes it back to disk as well. It then closes the file under GS/OS, and disposes of the memory it used to hold the map. If you re-size a resource, or add or remove a resource, this changes the ResRefRec as well, which is part of the map, and causes the mapFlag to be set.
In the early days of System 5, I wrote a program called ResLin, which displays resources and their names, and allows you to copy and edit them. Since then a number of programs have appeared, including DesignMaster (from Byte Works in the U.S.), Genisys (from SSSi, but available from AAPDA) and LLRE (Low Level Resource Editor). These utilities allow you to create all the resources your program needs, and can even export them as source code. Although DesignMaster and Genisys, which approach resources at an application level, are the two most powerful utilities, LLRE and ResLin do allow you to examine resources at their lowest level, hence the name, and change their attributes. LLRE is shareware, and my ResLin program is freeware. DesignMaster and Genisys are both commercial products, and at $300+ for Genisys, you'd want to be pretty serious about resources!
Well so much for the Resource Manager, the quiet manipulator.

THIS CONTENT COPYRIGHT © 2007, APPLE MACINTOSH USERS' GROUP, SYDNEY
Permission has been obtained to make this material available on the Internet.

Permission is hereby granted for non-profit user groups to republish this content.
PLEASE CREDIT THE AUTHOR AND THE SOURCE: Applecations, publication of the Apple Users' Group, Sydney, Australia

THIS PAGE COPYRIGHT © 2007, ANDREW ROUGHAN